package mornd.tomcat.test1;

import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistrarBeanPostProcessor;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.view.BeanNameViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Map;

/**
 * @author: mornd
 * @dateTime: 2023/5/9 - 15:00
 */

@Configuration
@ComponentScan
public class WebConfig {

    // 注册内嵌 tomcat web 服务器
    @Bean
    public TomcatServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory();
        return webServerFactory;
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }

    @Bean
    public RequestMappingHandlerMapping handlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    @Bean
    public RequestMappingHandlerAdapter handlerAdapter() {
        RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
        // 默认的处理器适配器不会携带消息转换器，需要手动添加
        handlerAdapter.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
        return handlerAdapter;
    }

    /**
     * 改变 tomcat 默认处理错误页面的地址
    *  这里是使用 forward 方式跳转的
     * @return
     */
    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return new ErrorPageRegistrar() {
            @Override
            public void registerErrorPages(ErrorPageRegistry tomcatServletWebServerFactory) {
                // 手动添加错误页面跳转地址
                tomcatServletWebServerFactory.addErrorPages(new ErrorPage("/error"));
            }
        };
    }

    @Bean // 上面注册的错误页面还需要通过后处理器来处理
    public ErrorPageRegistrarBeanPostProcessor postProcessor() {
        return new ErrorPageRegistrarBeanPostProcessor();
    }

    // spring 提供的默认错误处理控制器
    @Bean
    public BasicErrorController basicErrorController() {
        ErrorProperties errorProperties = new ErrorProperties();
        // 是否返回服务器真实的异常信息
        errorProperties.setIncludeException(true);
        return new BasicErrorController(
                new DefaultErrorAttributes(), errorProperties);
    }

    /**
     * 处理浏览器访问时，返回的错误页面，bean的名称必须是 error，也就是方法名
     * @return
     */
    @Bean
    public View error() {
        return new View() {
            @Override
            public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().print("<h2>" + model + "</h2>");
            }
        };
    }

    /**
     * 根据 bean 名称注册 controller 处理请求，搭配上面的方法使用
     * @return
     */
    @Bean
    public ViewResolver viewResolver() {
        return new BeanNameViewResolver();
    }

}
